#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266HTTPUpdateServer.h>
#include <Wire.h>
#include "webctl.h"

#define LED_ON 0
#define LED_OFF 1

#define display Serial

HTMLUtil htmlUtil;

int gpioCtl = 14;
int InPutLast = 1;
bool isStateChange = true;
bool ledStateEnable = true;
ESP8266WiFiMulti WiFiMulti;

ESP8266WebServer server(80);
ESP8266HTTPUpdateServer httpUpdater;
WiFiServer wfserver = NULL;

const int led = LED_BUILTIN;
const int InPin = GPIO_ID_PIN(12);

char *strAdd(char *str1, char *str2) {
  char *str = (char *) malloc(strlen(str1) + strlen(str2));
  sprintf(str, "%s%s", str1, str2);
  return str;
}

void handleRoot() {
  digitalWrite(led, LED_OFF);
  server.send(200, "text/html", htmlUtil.rootBody());
  digitalWrite(led, LED_ON);
  display.print("handleRoot");
}

void handleSetgpio() {
  /*if (server.method() != HTTP_POST) {
    digitalWrite(led, LED_OFF);
    server.send(405, "text/plain", "Method Not Allowed");
    digitalWrite(led, LED_ON);
    return;
    }*/
  if (ledStateEnable) {
    digitalWrite(led, LED_OFF);
  }
  pinMode(InPin, INPUT);
  String message = "POST body was:\n" + server.arg("plain") + server.arg("pin") + server.arg("model") + server.arg("val");

  int gpoiPin = atoi(server.arg("pin").c_str());
  //GPOI引脚是否可用
  if (gpoiPin > 0) {
    //输入模式
    if (strcmp(server.arg("model").c_str(), "monitor") == 0) {
      pinMode((gpoiPin), INPUT);
      gpioCtl = gpoiPin;
      message += F("输入模式");
    } else if (strcmp(server.arg("model").c_str(), "in") == 0) {
      pinMode((gpoiPin), INPUT);
      message += F("输入模式");
    } else {
      pinMode((gpoiPin), OUTPUT);//GPIO_ID_PIN
      message += F("输出模式,");
      if (atoi(server.arg("val").c_str()) > 0) {
        digitalWrite(gpoiPin, 1 );
        message += F("高");
      } else {
        digitalWrite(gpoiPin,  0);
        message += F("低");
      }
    }
  }
  server.send(200, "text/plain", message);
  if (ledStateEnable) {
    digitalWrite(led, LED_ON);
  }
  display.println(message);
}

void handleGetgpio() {
  /*if (server.method() != HTTP_POST) {
    digitalWrite(led, LED_OFF);
    server.send(405, "text/plain", "Method Not Allowed");
    digitalWrite(led, LED_ON);
    return;
    }*/
  if (ledStateEnable) {
    digitalWrite(led, LED_OFF);
  }
  String message = "POST form was:\n";
  int gpoiPin = atoi(server.arg("pin").c_str());
  //GPOI引脚是否可用
  if (gpoiPin > 0) {
    int val = digitalRead(gpoiPin);
    message += (val) ? F("高") : F("低");
  } else {
    int val = digitalRead(gpioCtl);
    message += (val) ? F("高") : F("低");
  }
  server.send(200, "text/plain", message);
  display.println(message);
  if (ledStateEnable) {
    digitalWrite(led, LED_ON);
  }
}

void handleNotFound() {
  if (ledStateEnable) {
    digitalWrite(led, LED_OFF);
  }
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  Serial.print(message);
  if (ledStateEnable) {
    digitalWrite(led, LED_ON);
  }
}


void handleHttpData() {
  if (ledStateEnable) {
    digitalWrite(led, LED_OFF);
  }
  HTTPClient http;

  Serial.print("[HTTP] begin...\n");
  // configure traged server and url
  String url = server.arg("url");
  http.begin(url); //HTTP

  Serial.print("[HTTP] GET:\n");
  Serial.println(url);
  // start connection and send HTTP header
  int httpCode = http.GET();

  // httpCode will be negative on error
  if (httpCode > 0) {
    // HTTP header has been send and Server response header has been handled
    Serial.printf("[HTTP] GET... code: %d\n", httpCode);

    // file found at server
    if (httpCode == HTTP_CODE_OK) {
      String payload = http.getString();
      Serial.println(payload);
      server.send(httpCode, "text/plain", &payload[0]);
    } else {
      server.send(httpCode, "text/plain", "error");
    }

  } else {
    Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
  }

  http.end();
  if (ledStateEnable) {
    digitalWrite(led, LED_ON);
  }
}

void handleBaud() {
  if (ledStateEnable) {
    digitalWrite(led, LED_OFF);
  }
  String strBaud = server.arg("baud");
  int baud = atoi(strBaud.c_str());
  if (baud > 0) {
    Serial.printf("Baud:%s", strBaud.c_str());
    Serial.begin(baud);
    server.send(200, "text/plain", "设置成功：" + strBaud);
  } else {
    server.send(200, "text/plain", "设置失败");
  }
  if (ledStateEnable) {
    digitalWrite(led, LED_ON);
  }
}


void notify(char *msg) {
  Serial.println(msg);
  if (ledStateEnable) {
    digitalWrite(led, LED_OFF);
  }

  Serial.print("[HTTP] begin...\n");
  // configure traged server and url
  char *url = strAdd("http://jpf.vipgz2.idcfengye.com/notify/monitor.php?id=", msg);
  Serial.println(url);
  HTTPClient http;
  http.begin(url); //HTTP
  Serial.print("[HTTP] GET:\n");
  // start connection and send HTTP header
  int httpCode = http.GET();

  // httpCode will be negative on error
  if (httpCode > 0) {
    // HTTP header has been send and Server response header has been handled
    Serial.printf("[HTTP] GET... code: %d\n", httpCode);

    // file found at server
    if (httpCode == HTTP_CODE_OK) {
      String payload = http.getString();
      Serial.println(payload);
      server.send(httpCode, "text/plain", &payload[0]);
    } else {
      server.send(httpCode, "text/plain", "error");
    }

  } else {
    Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
  }

  http.end();
  if (ledStateEnable) {
    digitalWrite(led, LED_ON);
  }
}

void setup(void) {
  //OLED
  // Initialize display
  ledStateEnable = true;
  pinMode(gpioCtl, OUTPUT);
  digitalWrite(gpioCtl, 0);
  pinMode(led, OUTPUT);
  pinMode(InPin, INPUT);
  Serial.begin(115200);

  WiFi.mode(WIFI_STA);
  WiFiMulti.addAP("jj", "JPF@jj5201314");
  WiFiMulti.addAP("nmo", "e6gps1656");
  WiFiMulti.addAP("esp", "esp8266_");
  display.print("wifi Connecting...");
  // Wait for connection
  while (WiFiMulti.run() != WL_CONNECTED) {
    Serial.print("*");
    digitalWrite(led, LED_OFF);
    delay(500);
    digitalWrite(led, LED_ON);
    delay(500);
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID().c_str());
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  if (MDNS.begin("esp8266")) {
    Serial.println("MDNS responder started");
  }
  isStateChange = true;
  ledStateEnable = false;
}

void configServer(void)
{
  server.on("/root", handleRoot);
  server.on("/setgpio", handleSetgpio);

  server.on("/getgpio", handleGetgpio );
  server.on("/httpData", handleHttpData);
  server.on("/baud", handleBaud);

  server.onNotFound(handleNotFound);

  server.begin();
  httpUpdater.setup(&server);
  Serial.println("HTTP server started");
  MDNS.addService("http", "tcp", 80);
}

void showInputState() {
  if (InPutLast > 0) {
    Serial.println("on");
    notify("on");
  } else {
    notify("off");
    Serial.println("off");
  }
}


String comdata = "";//声明字符串变量
void loop(void) {
  // wait for data to be available
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print("*");
    digitalWrite(led, LED_OFF);
    delay(500);
    digitalWrite(led, LED_ON);
    delay(500);
    isStateChange = true;
  }
  if (isStateChange) {
    configServer();
    isStateChange = false;
    String ip = WiFi.localIP().toString();
    String ssid = WiFi.SSID();
    char *wifiinfo = strAdd(&ssid[0], &ip[0]);
    display.print(wifiinfo);
    wfserver = server.getServer();
    notify(wifiinfo);
  } else if (digitalRead(InPin) != InPutLast) {
    Serial.print("State Changed:");
    InPutLast = digitalRead(InPin);
    showInputState();
  }
  MDNS.update();
  while (Serial.available() > 0)
  {
    comdata += char(Serial.read());
    delay(2);
  }
  if (comdata.length() > 0)
  {
    Serial.print("receive:");
    Serial.println(comdata);
    comdata = "";
  }
  if (wfserver.status() == CLOSED) {
    isStateChange = true;
  } else {
    server.handleClient();
  }
}
